from datastructure.link import list


class QueueEmpty(BaseException):
    pass


class QueueFull(BaseException):
    pass


class Queue:
    def __init__(self, maxsize):
        self.max_size = maxsize
        self._queue = list()
        self._lock = threading.Lock()
        self._read_cond = threading.Condition(self._lock)
        self._write_cond = threading.Condition(self._lock)

    def _is_full(self):
        return len(self._queue) == self.max_size

    def _is_empty(self):
        return len(self._queue) == 0

    def get(self, block=True):
        self._read_cond.acquire()
        try:
            while self._is_empty():
                # 唤醒写线程
                Queue.__notify(self._write_cond)
                if block:
                    # 等待对列有数据可读，并且获得锁时返回。
                    self._read_cond.wait()
                else:
                    raise QueueEmpty
            data = self._queue.pop()
            # 唤醒写线程
            Queue.__notify(self._write_cond)
        finally:
            self._read_cond.release()
        return data

    @staticmethod
    def __notify(cond, time_to_sleep=0.00001):
        cond.notify()
        # 睡眠的目的用于切换线程，用于测试
        # TODO: 移除下面代码
        time.sleep(time_to_sleep)

    def put(self, data, block=False):
        self._write_cond.acquire()
        try:
            while self._is_full():
                # 唤醒读线程
                Queue.__notify(self._read_cond)
                if block:
                    # 等待对列非满，并且获得锁时返回（由写线程唤醒）。
                    self._write_cond.wait()
                else:
                    raise QueueFull
            self._queue.append(data)
            # 唤醒读线程
            Queue.__notify(self._read_cond)
        finally:
            self._write_cond.release()


if __name__ == "__main__":
    import threadpool
    import threading

    queue = Queue(maxsize=10)
    threads = threadpool.ThreadPool(10)


    def wait_request_to_process():
        thread_id = threading.current_thread().ident
        # print("The worker {} is ready ... ...".format(thread_id))
        while True:
            data = queue.get(block=True)
            print("{} output: {}".format(thread_id, data))


    for t in range(10):
        request = threadpool.WorkRequest(callable_=wait_request_to_process)
        threads.putRequest(request)

    import random
    import time

    while True:
        d = random.randint(1, 10000)
        try:
            queue.put(d, block=True)
        except:
            pass
        # time.sleep(1)
